package xyz.xtt.equity.support;

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.equity.constants.ErrorMessage;
import xyz.xtt.equity.exception.ChainException;

/**
 * 国美靓号api接口
 *
 * @author dale
 * @since 2024/12/31
 **/
@Component
@RefreshScope
@Slf4j
public class GomeLuckPhoneHttpService {
	@Value("${gome.luck.phone.channel.account}")
	private String channelAccount;
	@Value("${gome.luck.phone.channel.secret}")
	private String channelSecret;
	@Value("${gome.luck.phone.url}")
	private String fetchUrl;

	/**
	 * 预占号码
	 * 
	 * @param luckPhone
	 * @return
	 */
	public boolean preLockPhone(String luckPhone) {
		// 构造请求参数
		String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		Map<String, String> parameters = Map
				.of("channelAccount", channelAccount, "timeStamp", timeStamp, "sign", generateSign(timeStamp), "telephone", luckPhone);

		String formData = buildFormData(parameters);

		// 创建 HttpClient
		HttpClient client = HttpClient.newHttpClient();

		// 构造 POST 请求
		String url = fetchUrl + "/lockPhone";
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(URI.create(url))
				.header("Content-Type", "application/x-www-form-urlencoded")
				.header("Accept", "application/json; charset=utf-8")
				.POST(HttpRequest.BodyPublishers.ofString(formData))
				.build();
		log.info("preLockPhone Sending request to url:{} with params:{}", url, formData);

		// 发送请求并获取响应
		int maxTries = 4;
		while (maxTries-- > 0) {
			try {
				HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
				String body = decodeUnicode(response.body());
				JSONObject bodyObj = JSONUtil.parseObj(body);
				if (response.statusCode() == 200) {
					String state = bodyObj.getStr("state");
					if (Objects.equals(state, "0000")) {
						return true;
					} else {
						// 不可恢复异常打印日志后直接返回
						log.warn("preLockPhone error res:{}", body);
						if (Objects.equals(state, "2002")) {
							throw new ChainException(ErrorMessage.LUCK_PHONE_LOCK_FAIL);
						} else if (Objects.equals(state, "3001")) {
							throw new ChainException(ErrorMessage.LUCK_PHONE_CAN_NOT_USE);
						} else {
							throw new ChainException(ErrorMessage.ERROR_GENERAL);
						}
					}
				} else {
					// 可恢复异常打印日志后重试
					log.error("preLockPhone error statusCode:{} body:{}", body);
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
						Thread.currentThread().interrupt();
					}
				}
			} catch (Exception e) {
				if (e instanceof ChainException) {
					throw (ChainException) e;
				}
				log.error("preLockPhone error:{}", e.getMessage());
			}
		}
		throw new ChainException(ErrorMessage.ERROR_GENERAL);
	}

	/**
	 * 提交订单
	 * 
	 * @param luckPhone
	 * @param receiverPhone
	 * @param orderNo
	 * @param remark
	 * @return
	 */
	public boolean submitOrder(String luckPhone, String receiverPhone, long orderNo, String remark) {
		// 构造请求参数
		String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		Map<String, String> parameters = Map
				.of("channelAccount", channelAccount, "timeStamp", timeStamp, "sign", generateSign(timeStamp), "telephone", luckPhone, "orderNo", orderNo
						+ "", "receiverPhone", receiverPhone, "Remark", StringUtils.isNotBlank(remark) ? remark : "");

		String formData = buildFormData(parameters);

		// 创建 HttpClient
		HttpClient client = HttpClient.newHttpClient();

		// 构造 POST 请求
		String url = fetchUrl + "/postOrder";
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(URI.create(url))
				.header("Content-Type", "application/x-www-form-urlencoded")
				.header("Accept", "application/json; charset=utf-8")
				.POST(HttpRequest.BodyPublishers.ofString(formData))
				.build();

		// 发送请求并获取响应
		int maxTries = 4;
		while (maxTries-- > 0) {
			try {
				log.info("submitOrder Sending request to url:{} with params:{}", url, formData);
				HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
				String body = decodeUnicode(response.body());
				JSONObject bodyObj = JSONUtil.parseObj(body);
				if (response.statusCode() == 200) {
					String state = bodyObj.getStr("state");
					if (Objects.equals(state, "0000")) {
						return true;
					} else {
						log.warn("submitOrder error res:{}", body);
						if (Objects.equals(state, "2000") || Objects.equals(state, "2001") || Objects.equals(state, "3001")) {
							throw new ChainException(ErrorMessage.LUCK_PHONE_CAN_NOT_USE);
						}
					}
				} else {
					log.error("submitOrder error statusCode:{} body:{}", body);
				}
			} catch (Exception e) {
				if (e instanceof ChainException) {
					throw (ChainException) e;
				}
				log.error("submitOrder error:{}", e.getMessage());
			}
		}
		throw new ChainException(ErrorMessage.ERROR_GENERAL);
	}

	/**
	 * 获取订单状态
	 * 
	 * @param orderNo 业务方订单号
	 * @return 订单状态
	 */
	public Integer fetchOrderStatus(Long orderNo) {
		// 构造请求参数
		String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		Map<String, String> parameters = Map
				.of("channelAccount", channelAccount, "timeStamp", timeStamp, "sign", generateSign(timeStamp), "orderNo", orderNo + "");

		String formData = buildFormData(parameters);

		// 创建 HttpClient
		HttpClient client = HttpClient.newHttpClient();

		// 构造 POST 请求
		String url = fetchUrl + "/queryOrder";
		HttpRequest request = HttpRequest
				.newBuilder()
				.uri(URI.create(url))
				.header("Content-Type", "application/x-www-form-urlencoded")
				.header("Accept", "application/json; charset=utf-8")
				.POST(HttpRequest.BodyPublishers.ofString(formData))
				.build();

		// 发送请求并获取响应
		int maxTries = 4;
		while (maxTries-- > 0) {
			try {
				log.info("fetchOrderStatus Sending request to url:{} with params:{}", url, formData);
				HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
				String body = decodeUnicode(response.body());
				JSONObject bodyObj = JSONUtil.parseObj(body);
				if (response.statusCode() == 200 && Objects.equals(bodyObj.getStr("state"), "0000")) {
					return Integer.valueOf(bodyObj.getJSONObject("data").getStr("status"));
				} else {
					log.error("fetchOrderStatus error statusCode:{} body:{}", response.statusCode(), body);
				}
			} catch (Exception e) {
				log.error("fetchOrderStatus error:{}", e.getMessage());
			}
		}
		return null;
	}

	/**
	 * 生成签名
	 *
	 * @param timeStamp
	 * @return
	 */
	private String generateSign(String timeStamp) {
		return SecureUtil.md5(channelAccount + channelSecret + timeStamp).toLowerCase();
	}

	/**
	 * 将参数 Map 转换为 application/x-www-form-urlencoded 格式
	 *
	 * @param data
	 * @return
	 */
	private static String buildFormData(Map<String, String> data) {
		return data
				.entrySet()
				.stream()
				.map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
				.collect(Collectors.joining("&"));
	}

	/**
	 * 解码 Unicode 编码的字符串
	 *
	 * @param encoded
	 * @return
	 */
	private static String decodeUnicode(String encoded) {
		StringBuilder decoded = new StringBuilder();
		int i = 0;
		while (i < encoded.length()) {
			char c = encoded.charAt(i++);
			if (c == '\\' && i < encoded.length() && encoded.charAt(i) == 'u') {
				int codePoint = Integer.parseInt(encoded.substring(i + 1, i + 5), 16);
				decoded.append((char) codePoint);
				i += 5;
			} else {
				decoded.append(c);
			}
		}
		return decoded.toString();
	}

}
